﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections.Specialized;
using System.Collections;
using System.IO;

namespace Doo.WebUI
{
    /// <summary>
    /// 资源管理器
    /// 压缩并整合Script,Css以减小连接数
    /// </summary>
    public class ResourceManager
    {
        #region 组定义
        protected static OrderedDictionary ScriptResources = new OrderedDictionary();
        protected static OrderedDictionary CSSResources = new OrderedDictionary();

        protected static Hashtable ScriptFind = new Hashtable();
        protected static Hashtable CSSFind = new Hashtable();

        //Next Two For FileWatcher
        protected static Hashtable ScriptFindFullPath = new Hashtable();
        protected static Hashtable CSSFindFullPath = new Hashtable();

        /// <summary>
        /// 注册脚本对象
        /// </summary>
        /// <param name="group"></param>
        /// <param name="path"></param>
        public static void RegisterScriptItem(string group, string path)
        {
            if (ScriptResources[group] == null) ScriptResources[group] = new OrderedDictionary();
            (ScriptResources[group] as OrderedDictionary)[path] = true;
            ScriptFind[path] = group;
        }

        /// <summary>
        /// 注册脚本对象组
        /// </summary>
        /// <param name="group"></param>
        /// <param name="paths"></param>
        public static void RegisterScriptGroup(string group, string[] paths)
        {
            if (ScriptResources[group] == null) ScriptResources[group] = new OrderedDictionary();
            var od = ScriptResources[group] as OrderedDictionary;
            foreach (var p in paths) { od[p] = true; ScriptFind[p] = group; }
        }

        /// <summary>
        /// 注册样式表
        /// </summary>
        /// <param name="group"></param>
        /// <param name="path"></param>
        public static void RegisterCSSItem(string group, string path)
        {
            if (CSSResources[group] == null) CSSResources[group] = new OrderedDictionary();
            (CSSResources[group] as OrderedDictionary)[path] = true;
            CSSFind[path] = group;
        }

        /// <summary>
        /// 注册样式表组
        /// </summary>
        /// <param name="group"></param>
        /// <param name="paths"></param>
        public static void RegisterCSSGroup(string group, string[] paths)
        {
            if (CSSResources[group] == null) CSSResources[group] = new OrderedDictionary();
            var od = CSSResources[group] as OrderedDictionary;
            foreach (var p in paths) { od[p] = true; CSSFind[p] = group; }
        }

        public static Hashtable ScriptCombinded = new Hashtable();
        public static Hashtable CSSCombinded = new Hashtable();

        private static FileSystemWatcher scriptwatcher;
        private static FileSystemWatcher csswatcher;

        /// <summary>
        /// 获取已合并的文件
        /// </summary>
        /// <param name="group"></param>
        /// <returns></returns>
        public static string GetCombindedScriptFile(string group)
        {
            string file = ScriptCombinded[group] as string;
            if (file == null)
            {
                lock (ScriptCombinded)
                {
                    file = ScriptCombinded[group] as string;//再检查一次
                    if (file != null) return file;
                    //开始合并
                    StringBuilder sb = new StringBuilder();
                    OrderedDictionary files = ScriptResources[group] as OrderedDictionary;
                    if (files == null) throw new Exception("没有这个组" + group);
                    foreach (string f in files.Keys)
                    {
                        string fullpath = ScriptBasePath + f;
                        sb.Append(File.ReadAllText(fullpath));
                        ScriptFindFullPath[fullpath] = group;
                    }
                    ScriptCombinded[group] = file = group + ".js";
                    File.WriteAllText(ScriptSavePath + file, sb.ToString());
                    //Register FileWatcher
                    if (scriptwatcher == null) { scriptwatcher = new FileSystemWatcher(ScriptBasePath); scriptwatcher.Changed += new FileSystemEventHandler(scriptwatcher_Changed); }
                }
            }
            return file;
        }

        static void scriptwatcher_Changed(object sender, FileSystemEventArgs e)
        {
            string group = ScriptFindFullPath[e.FullPath] as string;
            if (group == null) return;
            ScriptCombinded[group] = null;
        }

        /// <summary>
        /// 获取已合并的文件
        /// </summary>
        /// <param name="group"></param>
        /// <returns></returns>
        public static string GetCombindedCSSFile(string group)
        {
            string file = CSSCombinded[group] as string;
            if (file == null)
            {
                lock (CSSCombinded)
                {
                    file = CSSCombinded[group] as string;//再检查一次
                    if (file != null) return file;
                    //开始合并
                    StringBuilder sb = new StringBuilder();
                    OrderedDictionary files = CSSResources[group] as OrderedDictionary;
                    if (files == null) throw new Exception("没有这个组" + group);
                    foreach (string f in files.Keys)
                    {
                        string fullpath = CSSBasePath + f;
                        sb.Append(File.ReadAllText(fullpath));
                        CSSFindFullPath[fullpath] = group;
                    }
                    CSSCombinded[group] = file = group + ".css";
                    File.WriteAllText(CSSSavePath + file, sb.ToString());
                    //Register FileWatcher
                    if (csswatcher == null) { csswatcher = new FileSystemWatcher(CSSBasePath); csswatcher.Changed += new FileSystemEventHandler(csswatcher_Changed); }
                }
            }
            return file;
        }

        static void csswatcher_Changed(object sender, FileSystemEventArgs e)
        {
            string group = CSSFindFullPath[e.FullPath] as string;
            if (group == null) return;
            CSSCombinded[group] = null;
        }

        #endregion

        protected Page Page;

        #region 目录定义

        /// <summary>
        /// 样式表基本目录[绝对路径]
        /// </summary>
        public static string CSSBasePath { get; set; }

        /// <summary>
        /// 脚本基本目录[绝对路径]
        /// </summary>
        public static string ScriptBasePath { get; set; }

        /// <summary>
        /// 样式表保存目录
        /// </summary>
        public static string CSSSavePath { get; set; }

        /// <summary>
        /// 样式表客户端访问目录
        /// </summary>
        public static string CSSClientPath { get; set; }

        /// <summary>
        /// 脚本保存目录
        /// </summary>
        public static string ScriptSavePath { get; set; }

        /// <summary>
        /// 脚本客户端访问目录
        /// </summary>
        public static string ScriptClientPath { get; set; }

        #endregion

        public ResourceManager(Page page)
        {
            Page = page;
            page.PreRenderComplete += new EventHandler(page_PreRenderComplete);
        }

        void page_PreRenderComplete(object sender, EventArgs e)
        {
            //向Page注册脚本项
            foreach (string group in RegistedScriptGroup.Keys)
            {
                ScriptManager.RegisterClientScriptInclude(Page, Page.GetType(), "Doo.Resource.Script." + group, ScriptClientPath + GetCombindedScriptFile(group));
            }
            //向Page注册样式表项
            foreach (string group in RegistedCSSGroup.Keys)
            {
                string fullpath = CSSClientPath + GetCombindedCSSFile(group);
                if (ScriptManager.GetCurrent(Page).IsInAsyncPostBack)
                {
                    ScriptManager.RegisterClientScriptBlock(Page, Page.GetType(), "Doo.CSS." + group, string.Format("Doo.Resources.RegCSS(\"{0}\",\"{1}\");", group, fullpath), true);
                }
                else
                {
                    AddCssReferenceToHeader(fullpath);
                }
            }
        }

        void AddCssReferenceToHeader(string fullpath)
        {
            ControlCollection cc = Page.Header == null ? Page.Form.Controls : Page.Header.Controls;
            cc.Add(new LiteralControl(string.Format("<link type=\"text/css\" rel=\"stylesheet\" href=\"{0}\"/>", fullpath)));
        }

        public OrderedDictionary RegistedScriptGroup = new OrderedDictionary();
        public OrderedDictionary RegistedCSSGroup = new OrderedDictionary();

        public void RegisterScript(string path)
        {
            string group = ScriptFind[path] as string;
            if (group == null) throw new Exception(string.Format("路径为{0}的脚本文件未加入到任何组中!", path));
            RegistedScriptGroup[group] = true;
        }

        public void RegisterCSS(string path)
        {
            string group = CSSFind[path] as string;
            if (group == null) throw new Exception(string.Format("路径为{0}的样式表未加入到任何组中!", path));
            RegistedCSSGroup[group] = true;
        }

        #region CSS资源

        public void RegisterCSS(Type type, string name)
        {
            string url = Page.ClientScript.GetWebResourceUrl(type, name);
            AddCssReferenceToHeader(url);
        }

        #endregion
    }
}
